library(rgdal)
library(ggplot2)
library(readr)
library(dplyr)

Function

plot_fort_maps2 <- function(data, fill_str, legend_title, plot_title, size=0.1){
  require(ggplot2)
  require(ggsn)
  require(broom)
  ggplot() +                                               # initialize ggplot object
    geom_polygon(                                          # make a polygon
      data = data,                                    # data frame
      aes_string(x = "long", y = "lat", group = "group",                # coordinates, and group them by polygons
                 fill = fill_str),
      size=size, color="black") +                # variable to use for filling
    scale_fill_brewer(name=legend_title, palette = "RdYlBu", direction = -1,
                      drop = FALSE) + # fill with brewer colors   # add title
    theme(line = element_blank(),
          axis.text=element_blank(),      # .. tickmarks..
          axis.title=element_blank(),
          legend.position="none",
          plot.margin = unit(c(0, 0, 0, 0), "cm"),
          #legend.text=element_text(size=15),
          #legend.title=element_text(size=17), # .. axis labels..
          panel.background = element_blank(), plot.title = element_text(size=5)) + ggtitle(plot_title)
}
shape_to_ggplot <- function(shape){
  require(broom)
  gg_data <- tidy(shape)
  data <- slot(shape, "data")
  shape[["polyID"]] <- sapply(slot(shape, "polygons"), function(x) slot(x, "ID"))
  gg_data <- merge(gg_data, shape, by.x="id", by.y="polyID")
  return(gg_data)
}
grid_arrange_shared_legend <- function(..., ncol = length(list(...)), nrow = 1, position = c("bottom", "right")) {
  plots <- list(...)
  position <- match.arg(position)
  g <- ggplotGrob(plots[[1]] + theme(legend.position = position))$grobs
  legend <- g[[which(sapply(g, function(x) x$name) == "guide-box")]]
  lheight <- sum(legend$height)
  lwidth <- sum(legend$width)
  gl <- lapply(plots, function(x) x + theme(legend.position="none"))
  gl <- c(gl, ncol = ncol, nrow = nrow)
  combined <- switch(position,
                     "bottom" = arrangeGrob(do.call(arrangeGrob, gl),
                                            legend,
                                            ncol = 1,
                                            heights = unit.c(unit(1, "npc") - lheight, lheight)),
                     "right" = arrangeGrob(do.call(arrangeGrob, gl),
                                           legend,
                                           ncol = 2,
                                           widths = unit.c(unit(1, "npc") - lwidth, lwidth)))
  grid.newpage()
  grid.draw(combined)
  # return gtable invisibly
  invisible(combined)
}
g_legend<-function(a.gplot){
  tmp <- ggplot_gtable(ggplot_build(a.gplot))
  leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
  legend <- tmp$grobs[[leg]]
  return(legend)}

Bairro Level Plots

bairro_shp <- readOGR("~/Documents/Harvard - SM80/Thesis/Fortaleza_Hom_RGit_PRIVATE_Files/Shapefiles/Shapefiles/Bairro/", "Bairros_from_CTs")
OGR data source with driver: ESRI Shapefile 
Source: "/Users/Sudipta/Documents/Harvard - SM80/Thesis/Fortaleza_Hom_RGit_PRIVATE_Files/Shapefiles/Shapefiles/Bairro", layer: "Bairros_from_CTs"
with 119 features
It has 4 fields
bairro_homs <- read_csv("~/Documents/Harvard - SM80/Thesis/Fortaleza_Hom_RGit_PRIVATE_Files/Bairro_SMR_IR_per_yr.csv", 
    col_types = cols(CD_GEOCODB = col_character()))
number of columns of result is not a multiple of vector length (arg 1)17 parsing failures.
row # A tibble: 5 x 5 col     row col   expected              actual file                                                                              expected   <int> <chr> <chr>                 <chr>  <chr>                                                                             actual 1  1854 pop   no trailing characte… e3     '~/Documents/Harvard - SM80/Thesis/Fortaleza_Hom_RGit_PRIVATE_Files/Bairro_SMR_I… file 2  1855 pop   no trailing characte… e3     '~/Documents/Harvard - SM80/Thesis/Fortaleza_Hom_RGit_PRIVATE_Files/Bairro_SMR_I… row 3  1856 pop   no trailing characte… e3     '~/Documents/Harvard - SM80/Thesis/Fortaleza_Hom_RGit_PRIVATE_Files/Bairro_SMR_I… col 4  1857 pop   no trailing characte… e3     '~/Documents/Harvard - SM80/Thesis/Fortaleza_Hom_RGit_PRIVATE_Files/Bairro_SMR_I… expected 5  1858 pop   no trailing characte… e3     '~/Documents/Harvard - SM80/Thesis/Fortaleza_Hom_RGit_PRIVATE_Files/Bairro_SMR_I…
... ................................. ... ............................................................................................................................ ........ ......................................................................................................................................................................................................................................................... ...... ..................................................................................................................................................... .... ..................................................................................................................................................... ... ..................................................................................................................................................... ... ..................................................................................................................................................... ........ .....................................................................................................................................................
See problems(...) for more details.
bairro_shp_gg <- shape_to_ggplot(bairro_shp)
Regions defined for each Polygons
column name ‘id’ is duplicated in the result

Aggregated plot of counts

bairro_agg_homs <- bairro_homs %>% group_by(CD_GEOCODB) %>% summarize(obs_count=sum(obs_count), SMR=mean(SMR_per_yr), IR=mean(IR_per_yr))
breaks <- quantile(bairro_agg_homs$obs_count, probs=c(seq(0,1,0.15),1))
bairro_shp_gg_count_agg <- bairro_shp_gg[,-1] %>% left_join(bairro_agg_homs[,c(1,2)], by=c("cod_ibge"="CD_GEOCODB")) %>% mutate(cut=cut(obs_count, breaks=breaks, include.lowest=TRUE))
Column `cod_ibge`/`CD_GEOCODB` joining factor and character vector, coercing into character vector
plot_fort_maps2(bairro_shp_gg_count_agg, "cut","Homicide counts", "Aggregate counts for 2001-17 by bairro") + theme(plot.title = element_text(size=10), legend.position = "right")

Aggregated plot of SMRs

breaks <- quantile(bairro_agg_homs$SMR, probs=c(seq(0,1,0.15),1))
bairro_shp_gg_count_agg <- bairro_shp_gg[,-1] %>% left_join(bairro_agg_homs[,c(1,3)], by=c("cod_ibge"="CD_GEOCODB")) %>% mutate(cut=cut(SMR, breaks=breaks, include.lowest=TRUE))
Column `cod_ibge`/`CD_GEOCODB` joining factor and character vector, coercing into character vector
plot_fort_maps2(bairro_shp_gg_count_agg, "cut","Homicide counts", "Aggregate SMR for 2001-17 by bairro") + theme(plot.title = element_text(size=10), legend.position = "right")

Aggregated plot of IRs

breaks <- quantile(bairro_agg_homs$IR, probs=c(seq(0,1,0.15),1))
bairro_shp_gg_count_agg <- bairro_shp_gg[,-1] %>% left_join(bairro_agg_homs[,c(1,4)], by=c("cod_ibge"="CD_GEOCODB")) %>% mutate(cut=cut(IR, breaks=breaks, include.lowest=TRUE))
Column `cod_ibge`/`CD_GEOCODB` joining factor and character vector, coercing into character vector
plot_fort_maps2(bairro_shp_gg_count_agg, "cut","Incidence Rate\n(per 100,000 PYs)", "Aggregate IR for 2001-17 by bairro") + theme(plot.title = element_text(size=10), legend.position = "right")

Count plots by year

breaks <- quantile(bairro_homs$obs_count, probs=c(seq(0,1,0.15),1))
bairro_shp_gg_count <- bairro_shp_gg[,-1] %>% left_join(spread(bairro_homs[,c(1:3)], YOD, obs_count), by=c("cod_ibge"="CD_GEOCODB")) %>% mutate_at(.funs = funs(cut = cut(., breaks=breaks, include.lowest=TRUE)), .vars = vars(`2001`:`2017`))
Column `cod_ibge`/`CD_GEOCODB` joining factor and character vector, coercing into character vector
count_plots <- sapply(2001:2017, function(x) plot_fort_maps2(bairro_shp_gg_count, paste0("`",x,"_cut`"), paste0("Homicide count for ",x), as.character(x)), simplify = FALSE)
library(gridExtra)
library(grid)
library(ggpubr)
library(cowplot)
plot <- count_plots[[1]] + theme(legend.position = "right", legend.text=element_text(size=5), legend.title=element_text(size=5), legend.key.size = unit(0.5,"line")) + guides(fill=guide_legend(title="Homicide Count"))
mylegend <- g_legend(plot)
grid_count <- do.call((plot_grid), c(count_plots, nrow=5)) + draw_grob(mylegend, 0.28, 0.08, 0.28, 0.08) 

IR plots by years

breaks <- quantile(bairro_homs$IR_per_yr, probs=c(seq(0,1,0.15),1), na.rm=TRUE)
bairro_shp_gg_IR <- bairro_shp_gg[,-1] %>% left_join(spread(bairro_homs[,c(1,2,7)], YOD, IR_per_yr), by=c("cod_ibge"="CD_GEOCODB")) %>% mutate_at(.funs = funs(cut = cut(., breaks=breaks, include.lowest=TRUE)), .vars = vars(`2001`:`2017`))
Column `cod_ibge`/`CD_GEOCODB` joining factor and character vector, coercing into character vector
IR_plots <- sapply(2001:2017, function(x) plot_fort_maps2(bairro_shp_gg_IR, paste0("`",x,"_cut`"), paste0("IR for ",x), as.character(x)), simplify = FALSE)
plot <- IR_plots[[1]] + theme(legend.position = "right", legend.text=element_text(size=5), legend.title=element_text(size=5), legend.key.size = unit(0.5,"line")) + guides(fill=guide_legend(title="Homicide IR"))
mylegend <- g_legend(plot)
grid_IR <- do.call((plot_grid), c(count_plots, nrow=5)) + draw_grob(mylegend, 0.28, 0.08, 0.28, 0.08)

SMR plots by years

breaks <- quantile(bairro_homs$SMR_per_yr, probs=c(seq(0,1,0.15),1), na.rm=TRUE)
bairro_shp_gg_SMR <- bairro_shp_gg[,-1] %>% left_join(spread(bairro_homs[,c(1,2,6)], YOD, SMR_per_yr), by=c("cod_ibge"="CD_GEOCODB")) %>% mutate_at(.funs = funs(cut = cut(., breaks=breaks, include.lowest=TRUE)), .vars = vars(`2001`:`2017`))
Column `cod_ibge`/`CD_GEOCODB` joining factor and character vector, coercing into character vector
SMR_plots <- sapply(2001:2017, function(x) plot_fort_maps2(bairro_shp_gg_SMR, paste0("`",x,"_cut`"), paste0("IR for ",x), as.character(x)), simplify = FALSE)
plot <- SMR_plots[[1]] + theme(legend.position = "right", legend.text=element_text(size=5), legend.title=element_text(size=5), legend.key.size = unit(0.5,"line")) + guides(fill=guide_legend(title="Homicide IR"))
mylegend <- g_legend(plot)
grid_SMR <- do.call((plot_grid), c(count_plots, nrow=5)) + draw_grob(mylegend, 0.28, 0.08, 0.28, 0.08)

CT level plots

CT_shp <- readOGR("~/Documents/Harvard - SM80/Thesis/Fortaleza_Hom_RGit_PRIVATE_Files/Shapefiles/Shapefiles/CTs/", "Corrected_CTs")
OGR data source with driver: ESRI Shapefile 
Source: "/Users/Sudipta/Documents/Harvard - SM80/Thesis/Fortaleza_Hom_RGit_PRIVATE_Files/Shapefiles/Shapefiles/CTs", layer: "Corrected_CTs"
with 3044 features
It has 13 fields
CT_homs <- read_csv("~/Documents/Harvard - SM80/Thesis/Fortaleza_Hom_RGit_PRIVATE_Files/CT_SMR_IR_per_yr-agg.csv", 
    col_types = cols(CD_GEOCODI = col_character()))
CT_shp_gg <- shape_to_ggplot(CT_shp)
Regions defined for each Polygons

Some CTs have homicides but non pop. We have to revisit these. For now, I am turning Inf IR and SMR to zero. At most there are 2 homicides per year in these CTs. Also NaN are pop zero, hom zero. Also turning these to zero.

CT_homs <- CT_homs %>% mutate(SMR_per_yr=replace(SMR_per_yr, SMR_per_yr==Inf | is.nan(SMR_per_yr), 0), IR_per_yr=replace(IR_per_yr, IR_per_yr==Inf | is.nan(IR_per_yr), 0)) %>% as.data.frame()

Aggregated plot of counts

CT_agg_homs <- CT_homs %>% group_by(CD_GEOCODI) %>% summarize(obs_count=sum(obs_count), SMR=mean(SMR_per_yr), IR=mean(IR_per_yr))
breaks <- quantile(CT_agg_homs$obs_count, probs=c(seq(0,1,0.15),1))
CT_shp_gg_count_agg <- CT_shp_gg[,-1] %>% left_join(CT_agg_homs[,c(1,2)], by="CD_GEOCODI") %>% mutate(cut=cut(obs_count, breaks=breaks, include.lowest=TRUE))
Column `CD_GEOCODI` joining factor and character vector, coercing into character vector
plot_fort_maps2(CT_shp_gg_count_agg, "cut","Homicide counts", "Aggregate counts for 2001-17 by CT") + theme(plot.title = element_text(size=10), legend.position = "right")

Aggregated plot of SMRs

breaks <- quantile(CT_agg_homs$SMR, probs=c(seq(0,1,0.15),1))
CT_shp_gg_count_agg <- CT_shp_gg[,-1] %>% left_join(CT_agg_homs[,c(1,3)], by="CD_GEOCODI") %>% mutate(cut=cut(SMR, breaks=breaks, include.lowest=TRUE))
Column `CD_GEOCODI` joining factor and character vector, coercing into character vector
plot_fort_maps2(CT_shp_gg_count_agg, "cut","SMR", "Aggregate SMR for 2001-17 by CT") + theme(plot.title = element_text(size=10), legend.position = "right")

Aggregated plot of IRs

breaks <- quantile(CT_agg_homs$IR, probs=c(seq(0,1,0.15),1))
CT_shp_gg_count_agg <- CT_shp_gg[,-1] %>% left_join(CT_agg_homs[,c(1,4)], by="CD_GEOCODI") %>% mutate(cut=cut(IR, breaks=breaks, include.lowest=TRUE))
Column `CD_GEOCODI` joining factor and character vector, coercing into character vector
plot_fort_maps2(CT_shp_gg_count_agg, "cut","Incidence Rate\n(per 100,000 PYs)", "Aggregate IR for 2001-17 by CT") + theme(plot.title = element_text(size=10), legend.position = "right")

Count plots by year

breaks <- c(0,1,2,3,4,10,35)
CT_shp_gg_count <- CT_shp_gg[,-1] %>% left_join(spread(CT_homs[,c(1:3)], YOD, obs_count), by="CD_GEOCODI") %>% mutate_at(.funs = funs(cut = cut(., breaks=breaks, include.lowest=TRUE)), .vars = vars(`2001`:`2017`))
Column `CD_GEOCODI` joining factor and character vector, coercing into character vector
count_plots <- sapply(2001:2017, function(x) plot_fort_maps2(CT_shp_gg_count, paste0("`",x,"_cut`"), paste0("Homicide count for ",x), as.character(x), size=0.05), simplify = FALSE)
library(gridExtra)
library(grid)
library(ggpubr)
library(cowplot)
plot <- count_plots[[1]] + theme(legend.position = "right", legend.text=element_text(size=5), legend.title=element_text(size=5), legend.key.size = unit(0.5,"line")) + guides(fill=guide_legend(title="Homicide Count"))
mylegend <- g_legend(plot)
grid_count <- do.call((plot_grid), c(count_plots, nrow=5)) + draw_grob(mylegend, 0.28, 0.08, 0.28, 0.08) 
grid_count

IR plots by years

breaks <- c(0,5,10,15,50,100,200,15000)
CT_shp_gg_IR <- CT_shp_gg[,-1] %>% left_join(spread(CT_homs[,c(1,2,7)], YOD, IR_per_yr), by="CD_GEOCODI") %>% mutate_at(.funs = funs(cut = cut(., breaks=breaks, labels=(c("[0,5]","(5,10]","(10,15]","(15,50]","(50,100]","(100,200]",">200")), include.lowest=TRUE)), .vars = vars(`2001`:`2017`))
Column `CD_GEOCODI` joining factor and character vector, coercing into character vector
IR_plots <- sapply(2001:2017, function(x) plot_fort_maps2(CT_shp_gg_IR, paste0("`",x,"_cut`"), paste0("IR for ",x), as.character(x)), simplify = FALSE)
plot <- IR_plots[[1]] + theme(legend.position = "right", legend.text=element_text(size=5), legend.title=element_text(size=5), legend.key.size = unit(0.5,"line")) + guides(fill=guide_legend(title="Homicide IR"))
mylegend <- g_legend(plot)
grid_IR <- do.call((plot_grid), c(count_plots, nrow=5)) + draw_grob(mylegend, 0.28, 0.08, 0.28, 0.08)
grid_IR

SMR plots by years

breaks <- c(0,1,2,5,10,15,50,400)
CT_shp_gg_SMR <- CT_shp_gg[,-1] %>% left_join(spread(CT_homs[,c(1,2,6)], YOD, SMR_per_yr), by="CD_GEOCODI") %>% mutate_at(.funs = funs(cut = cut(., breaks=breaks, labels=(c("[0,1]","(1,2]","(2,5]","(5,10]","(10,15]","(15,50]",">50")), include.lowest=TRUE)), .vars = vars(`2001`:`2017`))
Column `CD_GEOCODI` joining factor and character vector, coercing into character vector
SMR_plots <- sapply(2001:2017, function(x) plot_fort_maps2(CT_shp_gg_SMR, paste0("`",x,"_cut`"), paste0("IR for ",x), as.character(x)), simplify = FALSE)
plot <- SMR_plots[[1]] + theme(legend.position = "right", legend.text=element_text(size=5), legend.title=element_text(size=5), legend.key.size = unit(0.5,"line")) + guides(fill=guide_legend(title="SMR"))
mylegend <- g_legend(plot)
grid_SMR <- do.call((plot_grid), c(count_plots, nrow=5)) + draw_grob(mylegend, 0.28, 0.08, 0.28, 0.08)
grid_SMR

CT_shp_gg_SMR$SMR_time1 <- CT_shp_gg_SMR$`2001` + CT_shp_gg_SMR$`2002` + CT_shp_gg_SMR$`2003` + CT_shp_gg_SMR$`2004` + CT_shp_gg_SMR$`2005` + CT_shp_gg_SMR$`2006`
CT_shp_gg_SMR$SMR_time2 <- CT_shp_gg_SMR$`2001` + CT_shp_gg_SMR$`2002` + CT_shp_gg_SMR$`2003` + CT_shp_gg_SMR$`2004` + CT_shp_gg_SMR$`2005` + CT_shp_gg_SMR$`2006`
LS0tCnRpdGxlOiAiRGVzY3JpcHRpdmUgTWFwcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpgYGB7cn0KbGlicmFyeShyZ2RhbCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGRwbHlyKQpgYGAKCkZ1bmN0aW9uCmBgYHtyfQpwbG90X2ZvcnRfbWFwczIgPC0gZnVuY3Rpb24oZGF0YSwgZmlsbF9zdHIsIGxlZ2VuZF90aXRsZSwgcGxvdF90aXRsZSwgc2l6ZT0wLjEpewogIHJlcXVpcmUoZ2dwbG90MikKICByZXF1aXJlKGdnc24pCiAgcmVxdWlyZShicm9vbSkKICBnZ3Bsb3QoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluaXRpYWxpemUgZ2dwbG90IG9iamVjdAogICAgZ2VvbV9wb2x5Z29uKCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbWFrZSBhIHBvbHlnb24KICAgICAgZGF0YSA9IGRhdGEsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBkYXRhIGZyYW1lCiAgICAgIGFlc19zdHJpbmcoeCA9ICJsb25nIiwgeSA9ICJsYXQiLCBncm91cCA9ICJncm91cCIsICAgICAgICAgICAgICAgICMgY29vcmRpbmF0ZXMsIGFuZCBncm91cCB0aGVtIGJ5IHBvbHlnb25zCiAgICAgICAgICAgICAgICAgZmlsbCA9IGZpbGxfc3RyKSwKICAgICAgc2l6ZT1zaXplLCBjb2xvcj0iYmxhY2siKSArICAgICAgICAgICAgICAgICMgdmFyaWFibGUgdG8gdXNlIGZvciBmaWxsaW5nCiAgICBzY2FsZV9maWxsX2JyZXdlcihuYW1lPWxlZ2VuZF90aXRsZSwgcGFsZXR0ZSA9ICJSZFlsQnUiLCBkaXJlY3Rpb24gPSAtMSwKICAgICAgICAgICAgICAgICAgICAgIGRyb3AgPSBGQUxTRSkgKyAjIGZpbGwgd2l0aCBicmV3ZXIgY29sb3JzICAgIyBhZGQgdGl0bGUKICAgIHRoZW1lKGxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQ9ZWxlbWVudF9ibGFuaygpLCAgICAgICMgLi4gdGlja21hcmtzLi4KICAgICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAsIDAsIDAsIDApLCAiY20iKSwKICAgICAgICAgICNsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNSksCiAgICAgICAgICAjbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE3KSwgIyAuLiBheGlzIGxhYmVscy4uCiAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NSkpICsgZ2d0aXRsZShwbG90X3RpdGxlKQp9CgoKCnNoYXBlX3RvX2dncGxvdCA8LSBmdW5jdGlvbihzaGFwZSl7CiAgcmVxdWlyZShicm9vbSkKICBnZ19kYXRhIDwtIHRpZHkoc2hhcGUpCiAgZGF0YSA8LSBzbG90KHNoYXBlLCAiZGF0YSIpCiAgc2hhcGVbWyJwb2x5SUQiXV0gPC0gc2FwcGx5KHNsb3Qoc2hhcGUsICJwb2x5Z29ucyIpLCBmdW5jdGlvbih4KSBzbG90KHgsICJJRCIpKQogIGdnX2RhdGEgPC0gbWVyZ2UoZ2dfZGF0YSwgc2hhcGUsIGJ5Lng9ImlkIiwgYnkueT0icG9seUlEIikKICByZXR1cm4oZ2dfZGF0YSkKfQpncmlkX2FycmFuZ2Vfc2hhcmVkX2xlZ2VuZCA8LSBmdW5jdGlvbiguLi4sIG5jb2wgPSBsZW5ndGgobGlzdCguLi4pKSwgbnJvdyA9IDEsIHBvc2l0aW9uID0gYygiYm90dG9tIiwgInJpZ2h0IikpIHsKCiAgcGxvdHMgPC0gbGlzdCguLi4pCiAgcG9zaXRpb24gPC0gbWF0Y2guYXJnKHBvc2l0aW9uKQogIGcgPC0gZ2dwbG90R3JvYihwbG90c1tbMV1dICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gcG9zaXRpb24pKSRncm9icwogIGxlZ2VuZCA8LSBnW1t3aGljaChzYXBwbHkoZywgZnVuY3Rpb24oeCkgeCRuYW1lKSA9PSAiZ3VpZGUtYm94IildXQogIGxoZWlnaHQgPC0gc3VtKGxlZ2VuZCRoZWlnaHQpCiAgbHdpZHRoIDwtIHN1bShsZWdlbmQkd2lkdGgpCiAgZ2wgPC0gbGFwcGx5KHBsb3RzLCBmdW5jdGlvbih4KSB4ICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikpCiAgZ2wgPC0gYyhnbCwgbmNvbCA9IG5jb2wsIG5yb3cgPSBucm93KQoKICBjb21iaW5lZCA8LSBzd2l0Y2gocG9zaXRpb24sCiAgICAgICAgICAgICAgICAgICAgICJib3R0b20iID0gYXJyYW5nZUdyb2IoZG8uY2FsbChhcnJhbmdlR3JvYiwgZ2wpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHRzID0gdW5pdC5jKHVuaXQoMSwgIm5wYyIpIC0gbGhlaWdodCwgbGhlaWdodCkpLAogICAgICAgICAgICAgICAgICAgICAicmlnaHQiID0gYXJyYW5nZUdyb2IoZG8uY2FsbChhcnJhbmdlR3JvYiwgZ2wpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aHMgPSB1bml0LmModW5pdCgxLCAibnBjIikgLSBsd2lkdGgsIGx3aWR0aCkpKQoKICBncmlkLm5ld3BhZ2UoKQogIGdyaWQuZHJhdyhjb21iaW5lZCkKCiAgIyByZXR1cm4gZ3RhYmxlIGludmlzaWJseQogIGludmlzaWJsZShjb21iaW5lZCkKCn0KCmdfbGVnZW5kPC1mdW5jdGlvbihhLmdwbG90KXsKICB0bXAgPC0gZ2dwbG90X2d0YWJsZShnZ3Bsb3RfYnVpbGQoYS5ncGxvdCkpCiAgbGVnIDwtIHdoaWNoKHNhcHBseSh0bXAkZ3JvYnMsIGZ1bmN0aW9uKHgpIHgkbmFtZSkgPT0gImd1aWRlLWJveCIpCiAgbGVnZW5kIDwtIHRtcCRncm9ic1tbbGVnXV0KICByZXR1cm4obGVnZW5kKX0KYGBgCgojIyNCYWlycm8gTGV2ZWwgUGxvdHMKCmBgYHtyfQpiYWlycm9fc2hwIDwtIHJlYWRPR1IoIn4vRG9jdW1lbnRzL0hhcnZhcmQgLSBTTTgwL1RoZXNpcy9Gb3J0YWxlemFfSG9tX1JHaXRfUFJJVkFURV9GaWxlcy9TaGFwZWZpbGVzL1NoYXBlZmlsZXMvQmFpcnJvLyIsICJCYWlycm9zX2Zyb21fQ1RzIikKYGBgCgpgYGB7cn0KYmFpcnJvX2hvbXMgPC0gcmVhZF9jc3YoIn4vRG9jdW1lbnRzL0hhcnZhcmQgLSBTTTgwL1RoZXNpcy9Gb3J0YWxlemFfSG9tX1JHaXRfUFJJVkFURV9GaWxlcy9CYWlycm9fU01SX0lSX3Blcl95ci5jc3YiLCAKICAgIGNvbF90eXBlcyA9IGNvbHMoQ0RfR0VPQ09EQiA9IGNvbF9jaGFyYWN0ZXIoKSkpCmBgYApgYGB7cn0KYmFpcnJvX3NocF9nZyA8LSBzaGFwZV90b19nZ3Bsb3QoYmFpcnJvX3NocCkKYGBgCgpBZ2dyZWdhdGVkIHBsb3Qgb2YgY291bnRzCgpgYGB7cn0KYmFpcnJvX2FnZ19ob21zIDwtIGJhaXJyb19ob21zICU+JSBncm91cF9ieShDRF9HRU9DT0RCKSAlPiUgc3VtbWFyaXplKG9ic19jb3VudD1zdW0ob2JzX2NvdW50KSwgU01SPW1lYW4oU01SX3Blcl95ciksIElSPW1lYW4oSVJfcGVyX3lyKSkKYGBgCgpgYGB7cn0KYnJlYWtzIDwtIHF1YW50aWxlKGJhaXJyb19hZ2dfaG9tcyRvYnNfY291bnQsIHByb2JzPWMoc2VxKDAsMSwwLjE1KSwxKSkKYmFpcnJvX3NocF9nZ19jb3VudF9hZ2cgPC0gYmFpcnJvX3NocF9nZ1ssLTFdICU+JSBsZWZ0X2pvaW4oYmFpcnJvX2FnZ19ob21zWyxjKDEsMildLCBieT1jKCJjb2RfaWJnZSI9IkNEX0dFT0NPREIiKSkgJT4lIG11dGF0ZShjdXQ9Y3V0KG9ic19jb3VudCwgYnJlYWtzPWJyZWFrcywgaW5jbHVkZS5sb3dlc3Q9VFJVRSkpCnBsb3RfZm9ydF9tYXBzMihiYWlycm9fc2hwX2dnX2NvdW50X2FnZywgImN1dCIsIkhvbWljaWRlIGNvdW50cyIsICJBZ2dyZWdhdGUgY291bnRzIGZvciAyMDAxLTE3IGJ5IGJhaXJybyIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKYGBgCgpBZ2dyZWdhdGVkIHBsb3Qgb2YgU01ScwoKYGBge3J9CmJyZWFrcyA8LSBxdWFudGlsZShiYWlycm9fYWdnX2hvbXMkU01SLCBwcm9icz1jKHNlcSgwLDEsMC4xNSksMSkpCmJhaXJyb19zaHBfZ2dfY291bnRfYWdnIDwtIGJhaXJyb19zaHBfZ2dbLC0xXSAlPiUgbGVmdF9qb2luKGJhaXJyb19hZ2dfaG9tc1ssYygxLDMpXSwgYnk9YygiY29kX2liZ2UiPSJDRF9HRU9DT0RCIikpICU+JSBtdXRhdGUoY3V0PWN1dChTTVIsIGJyZWFrcz1icmVha3MsIGluY2x1ZGUubG93ZXN0PVRSVUUpKQpwbG90X2ZvcnRfbWFwczIoYmFpcnJvX3NocF9nZ19jb3VudF9hZ2csICJjdXQiLCJIb21pY2lkZSBjb3VudHMiLCAiQWdncmVnYXRlIFNNUiBmb3IgMjAwMS0xNyBieSBiYWlycm8iKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCmBgYAoKQWdncmVnYXRlZCBwbG90IG9mIElScwoKYGBge3J9CmJyZWFrcyA8LSBxdWFudGlsZShiYWlycm9fYWdnX2hvbXMkSVIsIHByb2JzPWMoc2VxKDAsMSwwLjE1KSwxKSkKYmFpcnJvX3NocF9nZ19jb3VudF9hZ2cgPC0gYmFpcnJvX3NocF9nZ1ssLTFdICU+JSBsZWZ0X2pvaW4oYmFpcnJvX2FnZ19ob21zWyxjKDEsNCldLCBieT1jKCJjb2RfaWJnZSI9IkNEX0dFT0NPREIiKSkgJT4lIG11dGF0ZShjdXQ9Y3V0KElSLCBicmVha3M9YnJlYWtzLCBpbmNsdWRlLmxvd2VzdD1UUlVFKSkKcGxvdF9mb3J0X21hcHMyKGJhaXJyb19zaHBfZ2dfY291bnRfYWdnLCAiY3V0IiwiSW5jaWRlbmNlIFJhdGVcbihwZXIgMTAwLDAwMCBQWXMpIiwgIkFnZ3JlZ2F0ZSBJUiBmb3IgMjAwMS0xNyBieSBiYWlycm8iKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCmBgYAoKCkNvdW50IHBsb3RzIGJ5IHllYXIKYGBge3J9CmJyZWFrcyA8LSBxdWFudGlsZShiYWlycm9faG9tcyRvYnNfY291bnQsIHByb2JzPWMoc2VxKDAsMSwwLjE1KSwxKSkKCmJhaXJyb19zaHBfZ2dfY291bnQgPC0gYmFpcnJvX3NocF9nZ1ssLTFdICU+JSBsZWZ0X2pvaW4oc3ByZWFkKGJhaXJyb19ob21zWyxjKDE6MyldLCBZT0QsIG9ic19jb3VudCksIGJ5PWMoImNvZF9pYmdlIj0iQ0RfR0VPQ09EQiIpKSAlPiUgbXV0YXRlX2F0KC5mdW5zID0gZnVucyhjdXQgPSBjdXQoLiwgYnJlYWtzPWJyZWFrcywgaW5jbHVkZS5sb3dlc3Q9VFJVRSkpLCAudmFycyA9IHZhcnMoYDIwMDFgOmAyMDE3YCkpCmBgYAoKYGBge3J9CmNvdW50X3Bsb3RzIDwtIHNhcHBseSgyMDAxOjIwMTcsIGZ1bmN0aW9uKHgpIHBsb3RfZm9ydF9tYXBzMihiYWlycm9fc2hwX2dnX2NvdW50LCBwYXN0ZTAoImAiLHgsIl9jdXRgIiksIHBhc3RlMCgiSG9taWNpZGUgY291bnQgZm9yICIseCksIGFzLmNoYXJhY3Rlcih4KSksIHNpbXBsaWZ5ID0gRkFMU0UpCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShncmlkKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShjb3dwbG90KQpwbG90IDwtIGNvdW50X3Bsb3RzW1sxXV0gKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwibGluZSIpKSArIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iSG9taWNpZGUgQ291bnQiKSkKbXlsZWdlbmQgPC0gZ19sZWdlbmQocGxvdCkKZ3JpZF9jb3VudCA8LSBkby5jYWxsKChwbG90X2dyaWQpLCBjKGNvdW50X3Bsb3RzLCBucm93PTUpKSArIGRyYXdfZ3JvYihteWxlZ2VuZCwgMC4yOCwgMC4wOCwgMC4yOCwgMC4wOCkgCmBgYAoKCklSIHBsb3RzIGJ5IHllYXJzCgpgYGB7cn0KYnJlYWtzIDwtIHF1YW50aWxlKGJhaXJyb19ob21zJElSX3Blcl95ciwgcHJvYnM9YyhzZXEoMCwxLDAuMTUpLDEpLCBuYS5ybT1UUlVFKQoKYmFpcnJvX3NocF9nZ19JUiA8LSBiYWlycm9fc2hwX2dnWywtMV0gJT4lIGxlZnRfam9pbihzcHJlYWQoYmFpcnJvX2hvbXNbLGMoMSwyLDcpXSwgWU9ELCBJUl9wZXJfeXIpLCBieT1jKCJjb2RfaWJnZSI9IkNEX0dFT0NPREIiKSkgJT4lIG11dGF0ZV9hdCguZnVucyA9IGZ1bnMoY3V0ID0gY3V0KC4sIGJyZWFrcz1icmVha3MsIGluY2x1ZGUubG93ZXN0PVRSVUUpKSwgLnZhcnMgPSB2YXJzKGAyMDAxYDpgMjAxN2ApKQpgYGAKCmBgYHtyfQpJUl9wbG90cyA8LSBzYXBwbHkoMjAwMToyMDE3LCBmdW5jdGlvbih4KSBwbG90X2ZvcnRfbWFwczIoYmFpcnJvX3NocF9nZ19JUiwgcGFzdGUwKCJgIix4LCJfY3V0YCIpLCBwYXN0ZTAoIklSIGZvciAiLHgpLCBhcy5jaGFyYWN0ZXIoeCkpLCBzaW1wbGlmeSA9IEZBTFNFKQoKcGxvdCA8LSBJUl9wbG90c1tbMV1dICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsImxpbmUiKSkgKyBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IkhvbWljaWRlIElSIikpCm15bGVnZW5kIDwtIGdfbGVnZW5kKHBsb3QpCmdyaWRfSVIgPC0gZG8uY2FsbCgocGxvdF9ncmlkKSwgYyhjb3VudF9wbG90cywgbnJvdz01KSkgKyBkcmF3X2dyb2IobXlsZWdlbmQsIDAuMjgsIDAuMDgsIDAuMjgsIDAuMDgpCmBgYAoKClNNUiBwbG90cyBieSB5ZWFycwpgYGB7cn0KYnJlYWtzIDwtIHF1YW50aWxlKGJhaXJyb19ob21zJFNNUl9wZXJfeXIsIHByb2JzPWMoc2VxKDAsMSwwLjE1KSwxKSwgbmEucm09VFJVRSkKCmJhaXJyb19zaHBfZ2dfU01SIDwtIGJhaXJyb19zaHBfZ2dbLC0xXSAlPiUgbGVmdF9qb2luKHNwcmVhZChiYWlycm9faG9tc1ssYygxLDIsNildLCBZT0QsIFNNUl9wZXJfeXIpLCBieT1jKCJjb2RfaWJnZSI9IkNEX0dFT0NPREIiKSkgJT4lIG11dGF0ZV9hdCguZnVucyA9IGZ1bnMoY3V0ID0gY3V0KC4sIGJyZWFrcz1icmVha3MsIGluY2x1ZGUubG93ZXN0PVRSVUUpKSwgLnZhcnMgPSB2YXJzKGAyMDAxYDpgMjAxN2ApKQpgYGAKCmBgYHtyfQpTTVJfcGxvdHMgPC0gc2FwcGx5KDIwMDE6MjAxNywgZnVuY3Rpb24oeCkgcGxvdF9mb3J0X21hcHMyKGJhaXJyb19zaHBfZ2dfU01SLCBwYXN0ZTAoImAiLHgsIl9jdXRgIiksIHBhc3RlMCgiSVIgZm9yICIseCksIGFzLmNoYXJhY3Rlcih4KSksIHNpbXBsaWZ5ID0gRkFMU0UpCgpwbG90IDwtIFNNUl9wbG90c1tbMV1dICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsImxpbmUiKSkgKyBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IkhvbWljaWRlIElSIikpCm15bGVnZW5kIDwtIGdfbGVnZW5kKHBsb3QpCmdyaWRfU01SIDwtIGRvLmNhbGwoKHBsb3RfZ3JpZCksIGMoY291bnRfcGxvdHMsIG5yb3c9NSkpICsgZHJhd19ncm9iKG15bGVnZW5kLCAwLjI4LCAwLjA4LCAwLjI4LCAwLjA4KQpgYGAKCgojIyMgQ1QgbGV2ZWwgcGxvdHMKCgoKYGBge3J9CkNUX3NocCA8LSByZWFkT0dSKCJ+L0RvY3VtZW50cy9IYXJ2YXJkIC0gU004MC9UaGVzaXMvRm9ydGFsZXphX0hvbV9SR2l0X1BSSVZBVEVfRmlsZXMvU2hhcGVmaWxlcy9TaGFwZWZpbGVzL0NUcy8iLCAiQ29ycmVjdGVkX0NUcyIpCmBgYAoKYGBge3J9CkNUX2hvbXMgPC0gcmVhZF9jc3YoIn4vRG9jdW1lbnRzL0hhcnZhcmQgLSBTTTgwL1RoZXNpcy9Gb3J0YWxlemFfSG9tX1JHaXRfUFJJVkFURV9GaWxlcy9DVF9TTVJfSVJfcGVyX3lyLWFnZy5jc3YiLCAKICAgIGNvbF90eXBlcyA9IGNvbHMoQ0RfR0VPQ09ESSA9IGNvbF9jaGFyYWN0ZXIoKSkpCmBgYApgYGB7cn0KQ1Rfc2hwX2dnIDwtIHNoYXBlX3RvX2dncGxvdChDVF9zaHApCmBgYApTb21lIENUcyBoYXZlIGhvbWljaWRlcyBidXQgbm9uIHBvcC4gV2UgaGF2ZSB0byByZXZpc2l0IHRoZXNlLiBGb3Igbm93LCBJIGFtIHR1cm5pbmcgSW5mIElSIGFuZCBTTVIgdG8gemVyby4gQXQgbW9zdCB0aGVyZSBhcmUgMiBob21pY2lkZXMgcGVyIHllYXIgaW4gdGhlc2UgQ1RzLiBBbHNvIE5hTiBhcmUgcG9wIHplcm8sIGhvbSB6ZXJvLiBBbHNvIHR1cm5pbmcgdGhlc2UgdG8gemVyby4KCmBgYHtyfQpDVF9ob21zIDwtIENUX2hvbXMgJT4lIG11dGF0ZShTTVJfcGVyX3lyPXJlcGxhY2UoU01SX3Blcl95ciwgU01SX3Blcl95cj09SW5mIHwgaXMubmFuKFNNUl9wZXJfeXIpLCAwKSwgSVJfcGVyX3lyPXJlcGxhY2UoSVJfcGVyX3lyLCBJUl9wZXJfeXI9PUluZiB8IGlzLm5hbihJUl9wZXJfeXIpLCAwKSkgJT4lIGFzLmRhdGEuZnJhbWUoKQpgYGAKCgpBZ2dyZWdhdGVkIHBsb3Qgb2YgY291bnRzCgpgYGB7cn0KQ1RfYWdnX2hvbXMgPC0gQ1RfaG9tcyAlPiUgZ3JvdXBfYnkoQ0RfR0VPQ09ESSkgJT4lIHN1bW1hcml6ZShvYnNfY291bnQ9c3VtKG9ic19jb3VudCksIFNNUj1tZWFuKFNNUl9wZXJfeXIpLCBJUj1tZWFuKElSX3Blcl95cikpCmBgYAoKYGBge3J9CmJyZWFrcyA8LSBxdWFudGlsZShDVF9hZ2dfaG9tcyRvYnNfY291bnQsIHByb2JzPWMoc2VxKDAsMSwwLjE1KSwxKSkKQ1Rfc2hwX2dnX2NvdW50X2FnZyA8LSBDVF9zaHBfZ2dbLC0xXSAlPiUgbGVmdF9qb2luKENUX2FnZ19ob21zWyxjKDEsMildLCBieT0iQ0RfR0VPQ09ESSIpICU+JSBtdXRhdGUoY3V0PWN1dChvYnNfY291bnQsIGJyZWFrcz1icmVha3MsIGluY2x1ZGUubG93ZXN0PVRSVUUpKQpwbG90X2ZvcnRfbWFwczIoQ1Rfc2hwX2dnX2NvdW50X2FnZywgImN1dCIsIkhvbWljaWRlIGNvdW50cyIsICJBZ2dyZWdhdGUgY291bnRzIGZvciAyMDAxLTE3IGJ5IENUIikgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApLCBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQpgYGAKCkFnZ3JlZ2F0ZWQgcGxvdCBvZiBTTVJzCgpgYGB7cn0KYnJlYWtzIDwtIHF1YW50aWxlKENUX2FnZ19ob21zJFNNUiwgcHJvYnM9YyhzZXEoMCwxLDAuMTUpLDEpKQpDVF9zaHBfZ2dfY291bnRfYWdnIDwtIENUX3NocF9nZ1ssLTFdICU+JSBsZWZ0X2pvaW4oQ1RfYWdnX2hvbXNbLGMoMSwzKV0sIGJ5PSJDRF9HRU9DT0RJIikgJT4lIG11dGF0ZShjdXQ9Y3V0KFNNUiwgYnJlYWtzPWJyZWFrcywgaW5jbHVkZS5sb3dlc3Q9VFJVRSkpCnBsb3RfZm9ydF9tYXBzMihDVF9zaHBfZ2dfY291bnRfYWdnLCAiY3V0IiwiU01SIiwgIkFnZ3JlZ2F0ZSBTTVIgZm9yIDIwMDEtMTcgYnkgQ1QiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCmBgYAoKQWdncmVnYXRlZCBwbG90IG9mIElScwoKYGBge3J9CmJyZWFrcyA8LSBxdWFudGlsZShDVF9hZ2dfaG9tcyRJUiwgcHJvYnM9YyhzZXEoMCwxLDAuMTUpLDEpKQpDVF9zaHBfZ2dfY291bnRfYWdnIDwtIENUX3NocF9nZ1ssLTFdICU+JSBsZWZ0X2pvaW4oQ1RfYWdnX2hvbXNbLGMoMSw0KV0sIGJ5PSJDRF9HRU9DT0RJIikgJT4lIG11dGF0ZShjdXQ9Y3V0KElSLCBicmVha3M9YnJlYWtzLCBpbmNsdWRlLmxvd2VzdD1UUlVFKSkKcGxvdF9mb3J0X21hcHMyKENUX3NocF9nZ19jb3VudF9hZ2csICJjdXQiLCJJbmNpZGVuY2UgUmF0ZVxuKHBlciAxMDAsMDAwIFBZcykiLCAiQWdncmVnYXRlIElSIGZvciAyMDAxLTE3IGJ5IENUIikgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApLCBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQpgYGAKCgpDb3VudCBwbG90cyBieSB5ZWFyCmBgYHtyfQpicmVha3MgPC0gYygwLDEsMiwzLDQsMTAsMzUpCgpDVF9zaHBfZ2dfY291bnQgPC0gQ1Rfc2hwX2dnWywtMV0gJT4lIGxlZnRfam9pbihzcHJlYWQoQ1RfaG9tc1ssYygxOjMpXSwgWU9ELCBvYnNfY291bnQpLCBieT0iQ0RfR0VPQ09ESSIpICU+JSBtdXRhdGVfYXQoLmZ1bnMgPSBmdW5zKGN1dCA9IGN1dCguLCBicmVha3M9YnJlYWtzLCBpbmNsdWRlLmxvd2VzdD1UUlVFKSksIC52YXJzID0gdmFycyhgMjAwMWA6YDIwMTdgKSkKYGBgCgpgYGB7cn0KY291bnRfcGxvdHMgPC0gc2FwcGx5KDIwMDE6MjAxNywgZnVuY3Rpb24oeCkgcGxvdF9mb3J0X21hcHMyKENUX3NocF9nZ19jb3VudCwgcGFzdGUwKCJgIix4LCJfY3V0YCIpLCBwYXN0ZTAoIkhvbWljaWRlIGNvdW50IGZvciAiLHgpLCBhcy5jaGFyYWN0ZXIoeCksIHNpemU9MC4wNSksIHNpbXBsaWZ5ID0gRkFMU0UpCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShncmlkKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShjb3dwbG90KQpwbG90IDwtIGNvdW50X3Bsb3RzW1sxXV0gKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwibGluZSIpKSArIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iSG9taWNpZGUgQ291bnQiKSkKbXlsZWdlbmQgPC0gZ19sZWdlbmQocGxvdCkKZ3JpZF9jb3VudCA8LSBkby5jYWxsKChwbG90X2dyaWQpLCBjKGNvdW50X3Bsb3RzLCBucm93PTUpKSArIGRyYXdfZ3JvYihteWxlZ2VuZCwgMC4yOCwgMC4wOCwgMC4yOCwgMC4wOCkgCmBgYAoKYGBge3J9CmdyaWRfY291bnQKYGBgCgoKSVIgcGxvdHMgYnkgeWVhcnMKCmBgYHtyfQpicmVha3MgPC0gYygwLDUsMTAsMTUsNTAsMTAwLDIwMCwxNTAwMCkKCkNUX3NocF9nZ19JUiA8LSBDVF9zaHBfZ2dbLC0xXSAlPiUgbGVmdF9qb2luKHNwcmVhZChDVF9ob21zWyxjKDEsMiw3KV0sIFlPRCwgSVJfcGVyX3lyKSwgYnk9IkNEX0dFT0NPREkiKSAlPiUgbXV0YXRlX2F0KC5mdW5zID0gZnVucyhjdXQgPSBjdXQoLiwgYnJlYWtzPWJyZWFrcywgbGFiZWxzPShjKCJbMCw1XSIsIig1LDEwXSIsIigxMCwxNV0iLCIoMTUsNTBdIiwiKDUwLDEwMF0iLCIoMTAwLDIwMF0iLCI+MjAwIikpLCBpbmNsdWRlLmxvd2VzdD1UUlVFKSksIC52YXJzID0gdmFycyhgMjAwMWA6YDIwMTdgKSkKYGBgCgpgYGB7cn0KSVJfcGxvdHMgPC0gc2FwcGx5KDIwMDE6MjAxNywgZnVuY3Rpb24oeCkgcGxvdF9mb3J0X21hcHMyKENUX3NocF9nZ19JUiwgcGFzdGUwKCJgIix4LCJfY3V0YCIpLCBwYXN0ZTAoIklSIGZvciAiLHgpLCBhcy5jaGFyYWN0ZXIoeCkpLCBzaW1wbGlmeSA9IEZBTFNFKQoKcGxvdCA8LSBJUl9wbG90c1tbMV1dICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsImxpbmUiKSkgKyBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IkhvbWljaWRlIElSIikpCm15bGVnZW5kIDwtIGdfbGVnZW5kKHBsb3QpCmdyaWRfSVIgPC0gZG8uY2FsbCgocGxvdF9ncmlkKSwgYyhjb3VudF9wbG90cywgbnJvdz01KSkgKyBkcmF3X2dyb2IobXlsZWdlbmQsIDAuMjgsIDAuMDgsIDAuMjgsIDAuMDgpCmBgYAoKYGBge3J9CmdyaWRfSVIKYGBgCgpTTVIgcGxvdHMgYnkgeWVhcnMKYGBge3J9CmJyZWFrcyA8LSBjKDAsMSwyLDUsMTAsMTUsNTAsNDAwKQoKQ1Rfc2hwX2dnX1NNUiA8LSBDVF9zaHBfZ2dbLC0xXSAlPiUgbGVmdF9qb2luKHNwcmVhZChDVF9ob21zWyxjKDEsMiw2KV0sIFlPRCwgU01SX3Blcl95ciksIGJ5PSJDRF9HRU9DT0RJIikgJT4lIG11dGF0ZV9hdCguZnVucyA9IGZ1bnMoY3V0ID0gY3V0KC4sIGJyZWFrcz1icmVha3MsIGxhYmVscz0oYygiWzAsMV0iLCIoMSwyXSIsIigyLDVdIiwiKDUsMTBdIiwiKDEwLDE1XSIsIigxNSw1MF0iLCI+NTAiKSksIGluY2x1ZGUubG93ZXN0PVRSVUUpKSwgLnZhcnMgPSB2YXJzKGAyMDAxYDpgMjAxN2ApKQpgYGAKCmBgYHtyfQpTTVJfcGxvdHMgPC0gc2FwcGx5KDIwMDE6MjAxNywgZnVuY3Rpb24oeCkgcGxvdF9mb3J0X21hcHMyKENUX3NocF9nZ19TTVIsIHBhc3RlMCgiYCIseCwiX2N1dGAiKSwgcGFzdGUwKCJJUiBmb3IgIix4KSwgYXMuY2hhcmFjdGVyKHgpKSwgc2ltcGxpZnkgPSBGQUxTRSkKCnBsb3QgPC0gU01SX3Bsb3RzW1sxXV0gKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwibGluZSIpKSArIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iU01SIikpCm15bGVnZW5kIDwtIGdfbGVnZW5kKHBsb3QpCmdyaWRfU01SIDwtIGRvLmNhbGwoKHBsb3RfZ3JpZCksIGMoY291bnRfcGxvdHMsIG5yb3c9NikpICsgZHJhd19ncm9iKG15bGVnZW5kLCAwLjcsIDAuMDcsIDAuNywgMC4wNykKYGBgCgpgYGB7cn0KZ3JpZF9TTVIKYGBgCgoKYGBge3J9CkNUX3NocF9nZ19TTVIkU01SX3RpbWUxIDwtIENUX3NocF9nZ19TTVIkYDIwMDFgICsgQ1Rfc2hwX2dnX1NNUiRgMjAwMmAgKyBDVF9zaHBfZ2dfU01SJGAyMDAzYCArIENUX3NocF9nZ19TTVIkYDIwMDRgICsgQ1Rfc2hwX2dnX1NNUiRgMjAwNWAgKyBDVF9zaHBfZ2dfU01SJGAyMDA2YApDVF9zaHBfZ2dfU01SJFNNUl90aW1lMiA8LSBDVF9zaHBfZ2dfU01SJGAyMDAxYCArIENUX3NocF9nZ19TTVIkYDIwMDJgICsgQ1Rfc2hwX2dnX1NNUiRgMjAwM2AgKyBDVF9zaHBfZ2dfU01SJGAyMDA0YCArIENUX3NocF9nZ19TTVIkYDIwMDVgICsgQ1Rfc2hwX2dnX1NNUiRgMjAwNmAKYGBgCgo=